#include "flash.h"

#define PAGE_SIZE	(2 * 1024)

extern UART_HandleTypeDef huart1;
extern unsigned char generalBuffer[120];
unsigned char pageBuffer[PAGE_SIZE]; // page大小为2k，是擦除的最小单位

// 删除指定扇区，及扇区个数
char FLASH_ErasePage(unsigned int addr,unsigned int len)
{
    HAL_FLASH_Unlock();     //解锁
	unsigned int flashEraseRet;
	unsigned int pageAddr = addr;
	unsigned int pageNumber = len;
	HAL_StatusTypeDef status = HAL_ERROR;
	FLASH_EraseInitTypeDef flashEraseInitType = {0};
	flashEraseInitType.TypeErase = FLASH_TYPEERASE_PAGES;
	flashEraseInitType.PageAddress = pageAddr;
	flashEraseInitType.NbPages = pageNumber;
	flashEraseInitType.Banks = FLASH_BANK_1;
	status = HAL_FLASHEx_Erase(&flashEraseInitType, &flashEraseRet);
    HAL_FLASH_Lock();

    return status;
}

void FLASH_Debug(unsigned int addr, unsigned char opType, unsigned int len)
{

	// 测试时，使用page缓冲
	unsigned char* data = generalBuffer;

	switch(opType)
	{
	case 1:
		FLASH_ErasePage(addr, 1);
		break;
	case 2:
		FLASH_DirectWriteData(addr, data, len);
		break;
	case 3:
		FLASH_ReadData(addr, data, len);
		break;
	case 4:
		FLASH_WriteData(addr, data, len);
		break;
	case 5:
		HAL_UART_Transmit(&huart1, data, len, 0xffff);
		HAL_UART_Transmit(&huart1, "\r\n", 2, 0xffff);
		break;
	case 0x30:
	case 0x31:
	case 0x32:
	case 0x33:
	case 0x34:
	case 0x35:
		for (int i = 0; i < len; ++i)
		{
			data[i] = opType;
		}
		break;
	}

}



						// 0x08010000
char FLASH_DirectWriteData(unsigned int addr, unsigned char* data, unsigned int len)
{
    HAL_FLASH_Unlock();
    for(int i = 0; i< len; i += 4)
    {
    	unsigned int wordData = data[i + 0] << 0 | data[i + 1] << 8 | data[i + 3] << 16 | data[i + 3] << 24;
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,addr + i, wordData); //向FLASH中写入
    }
    HAL_FLASH_Lock();
}

// 先将整个page读出来，判断是否全为0xff，如果不是，，覆盖指定内存，再擦，再直写，暂时未完成
char FLASH_WriteData(unsigned int addr, unsigned char* data, unsigned int len)
{
	char reReadWriteFlag = 0; //是否需要将文件读出来再写进去

	while(len > 0)
	{
		unsigned int curPageIdx = addr / PAGE_SIZE;
		unsigned int curPageOff = addr % PAGE_SIZE;
		unsigned int curPageLen = PAGE_SIZE - curPageOff;
		// 取较小值
		curPageLen = (curPageLen < len) ? curPageLen : len;

		// 本次要写的地址（可能在page开头，可能在page中间）
		// 本次要写的数据（可能在page开头，可能在page中间）
		// 本次要写的长度（可能是一个page，可能是部分page）
		// 先默认不需要重写，以此初始化参数
		unsigned int curWriteAddr = addr;
		unsigned char* curWriteData = data;
		unsigned int curWriteLen = curPageLen;

		// 根据buffer，读到指定地址
		FLASH_ReadData(curWriteAddr, pageBuffer, curWriteLen);
		for (int i = 0; i < curPageLen; ++i)
		{
			if (0xff != pageBuffer[i])
			{
				reReadWriteFlag = 1;
				break;
			}
		}
		if (1 == reReadWriteFlag)
		{
			// 需要重写时，所以真实起始地址为page开头，长度为整个page
			curWriteAddr = curPageIdx * PAGE_SIZE;
			curWriteData = pageBuffer;
			curWriteLen = PAGE_SIZE;
			// 将整个page的数据全部读出来，,擦除，修改数据后，整个page一起
			FLASH_ReadData(curWriteAddr, curWriteData, curWriteLen);
			FLASH_ErasePage(curWriteAddr, 1);
			// 更新变化的地方
			for (int i = 0; i < curPageLen; ++i)
			{
				curWriteData[curPageOff + i] = data[i];
			}
		}

		FLASH_DirectWriteData(curWriteAddr, curWriteData, curWriteLen);

		// 本次操作过后，地址变化，数据指针变化，长度变化
		addr += curPageLen;
		data += curPageLen;
		len -= curPageLen;
	}

}



void FLASH_ReadData(unsigned int addr, unsigned char* data, unsigned int len)
{
	for(unsigned int i = 0; i < len; i += 4)
	{
    	unsigned int wordData = *(int*)(addr + i);
		data[i + 0] = (wordData >> 0) & 0xff;
		data[i + 1] = (wordData >> 8) & 0xff;
		data[i + 2] = (wordData >> 16) & 0xff;
		data[i + 3] = (wordData >> 24) & 0xff;
	}
}
